package com.handinglian.ai.notice.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.apidoc.entity.ApidocParam;
import com.github.pagehelper.PageHelper;
import com.handinglian.ai.common.dto.CommonPage;
import com.handinglian.ai.common.util.FastJsonUtil;
import com.handinglian.ai.common.util.GeneralUtil;
import com.handinglian.ai.common.util.PropertyUtil;
import com.handinglian.ai.notice.dto.*;
import com.handinglian.ai.notice.entity.KeyGroup;
import com.handinglian.ai.notice.entity.KeyGroupDetail;
import com.handinglian.ai.notice.entity.Mass;
import com.handinglian.ai.notice.entity.Notice;
import com.handinglian.ai.notice.enums.ExecuteStateEnum;
import com.handinglian.ai.notice.enums.ImportStateEnum;
import com.handinglian.ai.notice.enums.MethodEnum;
import com.handinglian.ai.notice.mapper.NoticeMapper;
import com.handinglian.ai.notice.param.DtmfCollectParam;
import com.handinglian.ai.notice.param.NoticeCreateParam;
import com.handinglian.ai.notice.param.NoticeUpdateParam;
import com.handinglian.ai.notice.service.KeyGroupDetailService;
import com.handinglian.ai.notice.service.KeyGroupService;
import com.handinglian.ai.notice.service.MassService;
import com.handinglian.ai.notice.service.NoticeService;
import com.handinglian.ai.record.entity.CallDtmf;
import com.handinglian.ai.record.service.CallDtmfService;
import com.handinglian.ai.record.service.CallRecordService;
import com.handinglian.ai.template.dto.CallTemplateDto;
import com.handinglian.ai.template.service.CallTemplateService;
import com.handinglian.ai.template.service.MessageTemplateService;
import com.handinglian.ai.thirdparty.constants.YyConstants;
import com.handinglian.ai.thirdparty.dto.YyDtmfCollectDto;
import com.handinglian.ai.thirdparty.dto.YyDtmfRespDto;
import com.handinglian.ai.thirdparty.service.YunyiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@Service
public class NoticeServiceImpl implements NoticeService {
    @Autowired
    private NoticeMapper noticeMapper;
    @Autowired
    @Lazy
    private MassService massService;
    @Autowired
    private YunyiService yunyiService;
    @Autowired
    private CallDtmfService callDtmfService;
    @Autowired
    private CallRecordService callRecordService;
    @Autowired
    private KeyGroupDetailService keyGroupDetailService;
    @Autowired
    private KeyGroupService keyGroupService;
    @Value("${api.properties}")
    private String filePath;

    @Override
    @Transactional
    public int create(NoticeCreateParam createParam) throws Exception {
        Notice notice = FastJsonUtil.ObjectToObject(createParam, Notice.class);
        notice.setCreateTime(new Date());
        noticeMapper.insertSelective(notice);
        return notice.getId();
    }

    @Override
    public CommonPage<NoticeDto> listPage(String titleOrTemplate, String type, String category, String method, String executeState, String sortField, String sortOrder, Integer pageNum, Integer pageSize) {
        List<Integer> types = GeneralUtil.stringToIntegerList(type);
        Integer typeInt = null;
        if (CollUtil.isNotEmpty(types)&&types.size()==1){
            typeInt = types.get(0);
        }
        List<Integer> categorys = GeneralUtil.stringToIntegerList(category);
        List<Integer> methods = GeneralUtil.stringToIntegerList(method);
        PageHelper.startPage(pageNum, pageSize);
        List<NoticeDto> noticeDtos = noticeMapper.list(titleOrTemplate, typeInt, categorys, methods, sortField, sortOrder);

        noticeDtos.forEach(noticeDto -> {
            //计划通知人数
            Integer countNoticeMass = massService.countByNoticeId(noticeDto.getId());
            noticeDto.setPlanNoticeCount(countNoticeMass);

            //实际通知人数
            Integer countActualNum = callRecordService.countActualNum(noticeDto.getId());
            noticeDto.setActualNoticeCount(countActualNum);
        });

        Date now = new Date();
        //设置执行状态
        noticeDtos.forEach(noticeDto -> {
            if (Objects.nonNull(noticeDto.getActualTime())){
                noticeDto.setExecuteState(ExecuteStateEnum.EXECUTED.getKey());
            } else {
                noticeDto.setExecuteState(ExecuteStateEnum.NOT_EXECUTE.getKey());
            }
        });
        CommonPage<NoticeDto> commonPage = CommonPage.restPage(noticeDtos);
        if (StrUtil.isNotBlank(executeState)){
            List<Integer> executeStates = GeneralUtil.stringToIntegerList(executeState);
            noticeDtos = noticeDtos.stream().filter(noticeDto -> executeStates.contains(noticeDto.getExecuteState())).collect(Collectors.toList());
            commonPage.setList(noticeDtos);
        }

        return commonPage;
    }

    @Override
    @Transactional
    public int delete(Integer id) {
        return noticeMapper.deleteByPrimaryKey(id);
    }

    @Override
    @Transactional
    public int update(NoticeUpdateParam updateParam) {
        Notice notice = FastJsonUtil.ObjectToObject(updateParam, Notice.class);
        String date = DateUtil.formatDateTime(DateUtil.offsetMinute(new Date(),2));
        String noticeTime = updateParam.getNoticeTime();
        noticeTime = noticeTime.equals("0")? date.substring(0, date.length()-3)+":00":noticeTime;
        notice.setNoticeTime(DateUtil.parseDateTime(noticeTime));
        return noticeMapper.updateByPrimaryKeySelective(notice);
    }

    @Override
    @Transactional
    public int update(Notice notice) {
        return noticeMapper.updateByPrimaryKeySelective(notice);
    }

    @Override
    public NoticeBaseDto getNoticeBase(Integer id) {
        Notice notice = noticeMapper.selectByPrimaryKey(id);
        NoticeBaseDto noticeDto = FastJsonUtil.ObjToObjWithDateFormat(notice, NoticeBaseDto.class);

        if (StrUtil.isNotBlank(noticeDto.getActualTime())){
            noticeDto.setExecuteState(ExecuteStateEnum.EXECUTED.getKey());
        } else {
            noticeDto.setExecuteState(ExecuteStateEnum.NOT_EXECUTE.getKey());
        }

        Integer countNoticeMass = massService.countByNoticeId(noticeDto.getId());
        noticeDto.setPlanNoticeCount(countNoticeMass);
        noticeDto.setSuccessNum(0);
        noticeDto.setFailureNum(0);
        if (noticeDto.getExecuteState().equals(ExecuteStateEnum.EXECUTED.getKey())){
            //实际通知人数
            Integer countActualNum = callRecordService.countActualNum(noticeDto.getId());
            noticeDto.setSuccessNum(countActualNum);
            noticeDto.setFailureNum(countNoticeMass-countActualNum);
        }

        //统计按键信息
        List<NoticeKeyDto> noticeKeyDtos = new ArrayList<>();
        List<KeyGroupDetail> keyGroupDetails = keyGroupDetailService.listByNoticeId(noticeDto.getId());
        keyGroupDetails.forEach(keyGroupDetail -> {
            NoticeKeyDto noticeKeyDto = noticeMapper.getNoticeKey(noticeDto.getId(), keyGroupDetail.getKey());
            if (Objects.nonNull(noticeKeyDto)){
                noticeKeyDtos.add(noticeKeyDto);
            }
        });
        noticeDto.setNoticeKeyDtos(noticeKeyDtos);
        //todo 执行信息
        return noticeDto;
    }

    @Override
    public NoticeSimpleDto getSimple(Integer id) {
        Notice notice = noticeMapper.selectByPrimaryKey(id);
        NoticeSimpleDto noticeSimpleDto = FastJsonUtil.ObjToObjWithDateFormat(notice, NoticeSimpleDto.class);
        if (!notice.getType().equals(0)){
            KeyGroupDto keyGroupDto = keyGroupService.get(notice.getType());
            noticeSimpleDto.setKeyGroupId(keyGroupDto.getId());
            noticeSimpleDto.setKeyGroupName(keyGroupDto.getName());
        }
        if (Objects.nonNull(notice.getActualTime())){
            noticeSimpleDto.setExecuteState(ExecuteStateEnum.EXECUTED.getKey());
        } else {
            noticeSimpleDto.setExecuteState(ExecuteStateEnum.NOT_EXECUTE.getKey());
        }
        return noticeSimpleDto;
    }

    @Override
    public CommonPage<NoticeDetailDto> listDetail(Integer id, String nameOrPhoneOrAddress, String keyOrResult, String startTime, String endTime, String phoneStatus, String sortField, String sortOrder, Integer pageNum, Integer pageSize) {
        List<Integer> phoneStatuses = GeneralUtil.stringToIntegerList(phoneStatus);
        Integer notExecute = null;
        if (phoneStatuses.contains(-1)){
            phoneStatuses.remove(new Integer(-1));
            notExecute = 1;
        }

        String key = "";
        if (StrUtil.isNotBlank(keyOrResult)){
            key = keyOrResult.startsWith("不")?"0":(keyOrResult.startsWith("同")?"1":(keyOrResult.startsWith("无")?"-1":keyOrResult));
        }
        List<NoticeKeyDto> noticeKeyDtos = noticeMapper.listNoticeKey(id);
        Date sTime = null;
        Date eTime = null;
        if (StrUtil.isNotBlank(startTime)&&StrUtil.isNotBlank(endTime)){
            sTime = DateUtil.parseDateTime(startTime+" 00:00:00");
            eTime = DateUtil.parseDateTime(endTime+" 23:59:59");
        }
        PageHelper.startPage(pageNum, pageSize);
        List<NoticeDetailDto> noticeDetailDtos = noticeMapper.listDetail(id, nameOrPhoneOrAddress, key, sTime, eTime, phoneStatuses, notExecute, sortField, sortOrder);

        noticeDetailDtos.forEach(noticeDetailDto -> {
            //设置状态
            if (Objects.isNull(noticeDetailDto.getPhoneStatus())){
                noticeDetailDto.setPhoneStatus(-1);
            } else if (Objects.nonNull(noticeDetailDto.getDtmf())){
                //设置回复结果
                String dtmf = noticeDetailDto.getDtmf();
                noticeKeyDtos.forEach(noticeKeyDto -> {
                    if (dtmf.startsWith(noticeKeyDto.getKey())){
                        String keyResult = noticeKeyDto.getValue()+"("+noticeKeyDto.getKey()+")";
                        noticeDetailDto.setDtmf(keyResult);
                    }
                });
                if (StrUtil.isBlank(noticeDetailDto.getDtmf())){
                    noticeDetailDto.setDtmf("无操作");
                }
            }
        });
        return CommonPage.restPage(noticeDetailDtos);
    }

    @Override
    @Transactional
    public int deleteDetail(Integer massId) {
        return massService.delete(massId);
    }

    @Override
    @Transactional
    public int deleteDetailBatch(List<Integer> massIds) {
        return massService.deleteBatch(massIds);
    }

    @Override
    @Transactional
    public int deleteBatch(String id) {
        List<Integer> ids = GeneralUtil.stringToIntegerList(id);
        return noticeMapper.deleteByIdIn(ids);
    }

    @Override
    @Transactional
    public void censusNotice() {
        //获取分钟级别时间
        String date = DateUtil.formatDateTime(new Date());
        date = date.substring(0, date.length()-3)+":00";
        Date noticeTime = DateUtil.parseDateTime(date);

        List<Mass> masses =  massService.list(noticeTime);
        if (CollUtil.isEmpty(masses)){
            return;
        }
        Map<Integer, Long> noticeIdCount = masses.stream().collect(Collectors.groupingBy(Mass::getNoticeId, Collectors.counting()));
        Set<Integer> noticeIds = noticeIdCount.keySet();
        List<NoticeTemplateDto> noticeTemplateDtos = noticeMapper.findNoticeTemplateByIdIn(noticeIds);
        noticeMapper.updateActualTimeByIdIn(new Date(), noticeIds);
        List<DtmfCollectParam> dtmfCollectParams = getDtmfCollect(masses, noticeTemplateDtos);

        dtmfCollectParams.forEach(dtmfCollectParam -> {
            try {
                YyDtmfRespDto yyDtmfRespDto = yunyiService.dtmfCollect(dtmfCollectParam);
                CallDtmf callDtmf = new CallDtmf();
                callDtmf.setNoticeId(dtmfCollectParam.getNoticeId());
                callDtmf.setRequestUuid(yyDtmfRespDto.getRequestUUID());
                callDtmf.setMassId(dtmfCollectParam.getMassId());
                callDtmfService.create(callDtmf);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

    }

    private List<DtmfCollectParam> getDtmfCollect(List<Mass> masses, List<NoticeTemplateDto> noticeTemplateDtos){
        List<DtmfCollectParam> dtmfCollectParams = new ArrayList<>();
        String dtmfNoticeUrl = PropertyUtil.getProperty(filePath, YyConstants.DTMF_NOTICE_URL);
        masses.forEach(mass -> {
            DtmfCollectParam dtmfCollectParam = new DtmfCollectParam();
            dtmfCollectParam.setMassId(mass.getId());
            dtmfCollectParam.setNoticeId(mass.getNoticeId());
            dtmfCollectParam.setCalleeNum(mass.getMobilePhone());
            dtmfCollectParam.setCalleeDisplayNum("+8657456189167");
            dtmfCollectParam.setDtmfLength("1");
            dtmfCollectParam.setDtmfNoticeUrl(dtmfNoticeUrl);
            noticeTemplateDtos.forEach(noticeTemplateDto -> {
                if (mass.getNoticeId().equals(noticeTemplateDto.getId())){
                    String templateContent = noticeTemplateDto.getTemplateContent();
                    templateContent = templateContent.replace("{预约时间}",DateUtil.formatDateTime(mass.getAppointmentTime()))
                            .replace("{姓名}",mass.getName());
                    dtmfCollectParam.setPlayText(templateContent);
                }
            });
            dtmfCollectParams.add(dtmfCollectParam);
        });
        return dtmfCollectParams;
    }

    public static void main(String[] args) {
        String str = "{姓名}你好，{预约时间}我们回来";
        str = str.replace("{姓名}","潘晓雷")
                .replace("{预约时间}","2019-01-01");
        System.out.println(str);
    }

    @Override
    public Notice get(Integer id) {
        return noticeMapper.selectByPrimaryKey(id);
    }

    @Override
    public Integer countCallTemplate(Integer templateId) {
        return noticeMapper.countCallTemplate(templateId);
    }

    @Override
    public Integer countMessageTemplate(Integer templateId) {
        return noticeMapper.countMessageTemplate(templateId);
    }

    public Integer countKeyGroup(Integer keyGroupId) {
        return noticeMapper.countByType(keyGroupId);
    }
}
